1   /*
2    * Copyright (C) 2011 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.testing;
18  
19  import static java.util.concurrent.TimeUnit.SECONDS;
20  
21  import com.google.common.annotations.Beta;
22  
23  import java.lang.ref.WeakReference;
24  import java.util.concurrent.CancellationException;
25  import java.util.concurrent.CountDownLatch;
26  import java.util.concurrent.ExecutionException;
27  import java.util.concurrent.Future;
28  import java.util.concurrent.TimeoutException;
29  
30  /**
31   * Testing utilities relating to garbage collection finalization.
32   *
33   * <p>Use this class to test code triggered by <em>finalization</em>, that is, one of the
34   * following actions taken by the java garbage collection system:
35   *
36   * <ul>
37   * <li>invoking the {@code finalize} methods of unreachable objects
38   * <li>clearing weak references to unreachable referents
39   * <li>enqueuing weak references to unreachable referents in their reference queue
40   * </ul>
41   *
42   * <p>This class uses (possibly repeated) invocations of {@link java.lang.System#gc()} to cause
43   * finalization to happen.  However, a call to {@code System.gc()} is specified to be no more
44   * than a hint, so this technique may fail at the whim of the JDK implementation, for example if
45   * a user specified the JVM flag {@code -XX:+DisableExplicitGC}.  But in practice, it works very
46   * well for ordinary tests.
47   *
48   * <p>Failure of the expected event to occur within an implementation-defined "reasonable" time
49   * period or an interrupt while waiting for the expected event will result in a {@link
50   * RuntimeException}.
51   *
52   * <p>Here's an example that tests a {@code finalize} method:
53   *
54   * <pre>   {@code
55   *   final CountDownLatch latch = new CountDownLatch(1);
56   *   Object x = new MyClass() {
57   *     ...
58   *     protected void finalize() { latch.countDown(); ... }
59   *   };
60   *   x = null;  // Hint to the JIT that x is stack-unreachable
61   *   GcFinalization.await(latch);}</pre>
62   *
63   * <p>Here's an example that uses a user-defined finalization predicate:
64   *
65   * <pre>   {@code
66   *   final WeakHashMap<Object, Object> map = new WeakHashMap<Object, Object>();
67   *   map.put(new Object(), Boolean.TRUE);
68   *   GcFinalization.awaitDone(new FinalizationPredicate() {
69   *     public boolean isDone() {
70   *       return map.isEmpty();
71   *     }
72   *   });}</pre>
73   *
74   * <p>Even if your non-test code does not use finalization, you can
75   * use this class to test for leaks, by ensuring that objects are no
76   * longer strongly referenced:
77   *
78   * <pre> {@code
79   * // Helper function keeps victim stack-unreachable.
80   * private WeakReference<Foo> fooWeakRef() {
81   *   Foo x = ....;
82   *   WeakReference<Foo> weakRef = new WeakReference<Foo>(x);
83   *   // ... use x ...
84   *   x = null;  // Hint to the JIT that x is stack-unreachable
85   *   return weakRef;
86   * }
87   * public void testFooLeak() {
88   *   GcFinalization.awaitClear(fooWeakRef());
89   * }}</pre>
90   *
91   * <p>This class cannot currently be used to test soft references, since this class does not try to
92   * create the memory pressure required to cause soft references to be cleared.
93   *
94   * <p>This class only provides testing utilities.  It is not designed for direct use in production
95   * or for benchmarking.
96   *
97   * @author mike nonemacher
98   * @author Martin Buchholz
99   * @since 11.0
100  */
101 @Beta
102 public final class GcFinalization {
103   private GcFinalization() {}
104 
105   /**
106    * 10 seconds ought to be long enough for any object to be GC'ed and finalized.  Unless we have a
107    * gigantic heap, in which case we scale by heap size.
108    */
109   private static long timeoutSeconds() {
110     // This class can make no hard guarantees.  The methods in this class are inherently flaky, but
111     // we try hard to make them robust in practice.  We could additionally try to add in a system
112     // load timeout multiplier.  Or we could try to use a CPU time bound instead of wall clock time
113     // bound.  But these ideas are harder to implement.  We do not try to detect or handle a
114     // user-specified -XX:+DisableExplicitGC.
115     //
116     // TODO(user): Consider using
117     // java/lang/management/OperatingSystemMXBean.html#getSystemLoadAverage()
118     //
119     // TODO(user): Consider scaling by number of mutator threads,
120     // e.g. using Thread#activeCount()
121     return Math.max(10L, Runtime.getRuntime().totalMemory() / (32L * 1024L * 1024L));
122   }
123 
124   /**
125    * Waits until the given future {@linkplain Future#isDone is done}, invoking the garbage
126    * collector as necessary to try to ensure that this will happen.
127    *
128    * @throws RuntimeException if timed out or interrupted while waiting
129    */
130   public static void awaitDone(Future<?> future) {
131     if (future.isDone()) {
132       return;
133     }
134     final long timeoutSeconds = timeoutSeconds();
135     final long deadline = System.nanoTime() + SECONDS.toNanos(timeoutSeconds);
136     do {
137       System.runFinalization();
138       if (future.isDone()) {
139         return;
140       }
141       System.gc();
142       try {
143         future.get(1L, SECONDS);
144         return;
145       } catch (CancellationException ok) {
146         return;
147       } catch (ExecutionException ok) {
148         return;
149       } catch (InterruptedException ie) {
150         throw new RuntimeException("Unexpected interrupt while waiting for future", ie);
151       } catch (TimeoutException tryHarder) {
152         /* OK */
153       }
154     } while (System.nanoTime() - deadline < 0);
155     throw new RuntimeException(
156         String.format("Future not done within %d second timeout", timeoutSeconds));
157   }
158 
159   /**
160    * Waits until the given latch has {@linkplain CountDownLatch#countDown counted down} to zero,
161    * invoking the garbage collector as necessary to try to ensure that this will happen.
162    *
163    * @throws RuntimeException if timed out or interrupted while waiting
164    */
165   public static void await(CountDownLatch latch) {
166     if (latch.getCount() == 0) {
167       return;
168     }
169     final long timeoutSeconds = timeoutSeconds();
170     final long deadline = System.nanoTime() + SECONDS.toNanos(timeoutSeconds);
171     do {
172       System.runFinalization();
173       if (latch.getCount() == 0) {
174         return;
175       }
176       System.gc();
177       try {
178         if (latch.await(1L, SECONDS)) {
179           return;
180         }
181       } catch (InterruptedException ie) {
182         throw new RuntimeException("Unexpected interrupt while waiting for latch", ie);
183       }
184     } while (System.nanoTime() - deadline < 0);
185     throw new RuntimeException(
186         String.format("Latch failed to count down within %d second timeout", timeoutSeconds));
187   }
188 
189   /**
190    * Creates a garbage object that counts down the latch in its finalizer.  Sequestered into a
191    * separate method to make it somewhat more likely to be unreachable.
192    */
193   private static void createUnreachableLatchFinalizer(final CountDownLatch latch) {
194     new Object() { @Override protected void finalize() { latch.countDown(); }};
195   }
196 
197   /**
198    * A predicate that is expected to return true subsequent to <em>finalization</em>, that is, one
199    * of the following actions taken by the garbage collector when performing a full collection in
200    * response to {@link System#gc()}:
201    *
202    * <ul>
203    * <li>invoking the {@code finalize} methods of unreachable objects
204    * <li>clearing weak references to unreachable referents
205    * <li>enqueuing weak references to unreachable referents in their reference queue
206    * </ul>
207    */
208   public interface FinalizationPredicate {
209     boolean isDone();
210   }
211 
212   /**
213    * Waits until the given predicate returns true, invoking the garbage collector as necessary to
214    * try to ensure that this will happen.
215    *
216    * @throws RuntimeException if timed out or interrupted while waiting
217    */
218   public static void awaitDone(FinalizationPredicate predicate) {
219     if (predicate.isDone()) {
220       return;
221     }
222     final long timeoutSeconds = timeoutSeconds();
223     final long deadline = System.nanoTime() + SECONDS.toNanos(timeoutSeconds);
224     do {
225       System.runFinalization();
226       if (predicate.isDone()) {
227         return;
228       }
229       CountDownLatch done = new CountDownLatch(1);
230       createUnreachableLatchFinalizer(done);
231       await(done);
232       if (predicate.isDone()) {
233         return;
234       }
235     } while (System.nanoTime() - deadline < 0);
236     throw new RuntimeException(
237         String.format("Predicate did not become true within %d second timeout", timeoutSeconds));
238   }
239 
240   /**
241    * Waits until the given weak reference is cleared, invoking the garbage collector as necessary
242    * to try to ensure that this will happen.
243    *
244    * <p>This is a convenience method, equivalent to:
245    * <pre>   {@code
246    *   awaitDone(new FinalizationPredicate() {
247    *     public boolean isDone() {
248    *       return ref.get() == null;
249    *     }
250    *   });}</pre>
251    *
252    * @throws RuntimeException if timed out or interrupted while waiting
253    */
254   public static void awaitClear(final WeakReference<?> ref) {
255     awaitDone(new FinalizationPredicate() {
256       public boolean isDone() {
257         return ref.get() == null;
258       }
259     });
260   }
261 
262   /**
263    * Tries to perform a "full" garbage collection cycle (including processing of weak references
264    * and invocation of finalize methods) and waits for it to complete.  Ensures that at least one
265    * weak reference has been cleared and one {@code finalize} method has been run before this
266    * method returns.  This method may be useful when testing the garbage collection mechanism
267    * itself, or inhibiting a spontaneous GC initiation in subsequent code.
268    *
269    * <p>In contrast, a plain call to {@link java.lang.System#gc()} does not ensure finalization
270    * processing and may run concurrently, for example, if the JVM flag {@code
271    * -XX:+ExplicitGCInvokesConcurrent} is used.
272    *
273    * <p>Whenever possible, it is preferable to test directly for some observable change resulting
274    * from GC, as with {@link #awaitClear}.  Because there are no guarantees for the order of GC
275    * finalization processing, there may still be some unfinished work for the GC to do after this
276    * method returns.
277    *
278    * <p>This method does not create any memory pressure as would be required to cause soft
279    * references to be processed.
280    *
281    * @throws RuntimeException if timed out or interrupted while waiting
282    * @since 12.0
283    */
284   public static void awaitFullGc() {
285     final CountDownLatch finalizerRan = new CountDownLatch(1);
286     WeakReference<Object> ref = new WeakReference<Object>(
287         new Object() {
288           @Override protected void finalize() { finalizerRan.countDown(); }
289         });
290 
291     await(finalizerRan);
292     awaitClear(ref);
293 
294     // Hope to catch some stragglers queued up behind our finalizable object
295     System.runFinalization();
296   }
297 }